//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_review_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_review_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/requirement_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/testcase_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_entry_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_review_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectReviewApiImpl) AddLink(ctx context.Context, req *project_review_api.AddLinkRequest) (*project_review_api.AddLinkResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := project_review_dao.ReviewDao.Exist(ctx, req.ProjectId, req.ReviewId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_NO_REVIEW,
			ErrMsg: "复盘记录不存在",
		}, nil
	}
	//检查目标是否存在
	exist = false
	if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_CONTENT {
		exist, err = project_entry_dao.EntryDao.Exist(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_SPRIT {
		entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
			exist = true
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_DOC {
		entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DOC) {
			exist = true
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_PAGES {
		entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_PAGES) {
			exist = true
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_API_COLL {
		entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
			exist = true
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_DRAW {
		entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DRAW) {
			exist = true
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_REQUIREMENT {
		exist, err = requirement_dao.RequirementInfoDao.Exist(ctx, req.ProjectId, req.LinkTargetId)
		if err != nil {
			return nil, err
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_BUG || req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_TASK {
		exist, err = issue_dao.IssueDao.Exist(ctx, req.ProjectId, req.LinkTargetId)
		if err != nil {
			return nil, err
		}
	} else if req.LinkType == project_review_api.LINK_TYPE_LINK_TYPE_TEST_CASE {
		exist, err = testcase_dao.CaseInfoDao.Exist(ctx, req.LinkTargetId, req.ProjectId)
		if err != nil {
			return nil, err
		}
	}
	if !exist {
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_NO_TARGET,
			ErrMsg: "链接目标不存在",
		}, nil
	}

	linkId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_review_dao.LinkDao.Insert(sessCtx, &project_review_dao.ReviewLinkItemDbItem{
			LinkId:       linkId,
			ProjectId:    req.ProjectId,
			ReviewId:     req.ReviewId,
			LinkType:     uint32(req.LinkType),
			LinkTargetId: req.LinkTargetId,
			TimeStamp:    nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &project_review_api.AddLinkResponse{
			Code:   project_review_api.AddLinkResponse_CODE_OK,
			LinkId: linkId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateReviewNotice{
		ProjectId: req.ProjectId,
		ReviewId:  req.ReviewId,
	})
	return ret.(*project_review_api.AddLinkResponse), nil
}

func (apiImpl *ProjectReviewApiImpl) RemoveLink(ctx context.Context, req *project_review_api.RemoveLinkRequest) (*project_review_api.RemoveLinkResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_review_api.RemoveLinkResponse{
			Code:   project_review_api.RemoveLinkResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_review_api.RemoveLinkResponse{
			Code:   project_review_api.RemoveLinkResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_review_api.RemoveLinkResponse{
			Code:   project_review_api.RemoveLinkResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_review_api.RemoveLinkResponse{
			Code:   project_review_api.RemoveLinkResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_review_api.RemoveLinkResponse{
			Code:   project_review_api.RemoveLinkResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := project_review_dao.ReviewDao.Exist(ctx, req.ProjectId, req.ReviewId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_review_api.RemoveLinkResponse{
			Code:   project_review_api.RemoveLinkResponse_CODE_NO_REVIEW,
			ErrMsg: "复盘记录不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_review_dao.LinkDao.Remove(sessCtx, req.ProjectId, req.ReviewId, req.LinkId)
		if err != nil {
			return nil, err
		}
		return &project_review_api.RemoveLinkResponse{
			Code: project_review_api.RemoveLinkResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateReviewNotice{
		ProjectId: req.ProjectId,
		ReviewId:  req.ReviewId,
	})
	return ret.(*project_review_api.RemoveLinkResponse), nil
}
